#include "RenderWidget.h"
const double PI = 3.1415927;
const double StraightAgnle = 180.0;
const double CameraSpeed = 0.25;

RenderWidget::RenderWidget( QWidget* parent )
: QGLWidget( parent )
{
// 	m_EyeX = 0.0;
// 	m_EyeY = -6.0;
// 	m_EyeZ = 6.0;
// 	m_EyeCenterX = 0.0;
// 	m_EyeCenterY = 0.0;
// 	m_EyeCenterZ = 0.0;
// 
// 	m_Longthofview_w = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY );
// 	m_Longthofview = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY + m_EyeZ*m_EyeZ );
// 	m_Elev = atan2 ( m_Longthofview_w, m_EyeZ );
// 	m_Angle = atan2 ( fabs(m_EyeY), m_EyeX );
	ResetViewPointInitial();

	m_render_width = parent->geometry().width();
	m_render_height = parent->geometry().height();

	setGeometry( 0, 0, m_render_width, m_render_height );
	QString str;

	startTimer(0);
	m_Pause = false;
}
RenderWidget::~RenderWidget()
{

}
void RenderWidget::ParseLog( const std::string& name )
{
	m_WorldModel.ParseLog( name );
}
void RenderWidget::initializeGL()
{
	glShadeModel( GL_SMOOTH );
	glClearColor( 0.35f, 0.53f, 0.70f, 0.0 );
	glClearDepth( 1.0 );
	glEnable( GL_DEPTH_TEST );
	glDepthFunc( GL_LEQUAL );
	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
}
void RenderWidget::paintGL()
{
 	glEnable(GL_COLOR_MATERIAL);
 
 	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 	glLoadIdentity();

	if( m_Elev >= PI )
	{
		m_Elev = PI;
	}
	else if( m_Elev <= 0.0 )
	{
		m_Elev = 0.0;
	}

	m_EyeCenterX = m_EyeX+m_Longthofview_w*cos(m_Angle);
	m_EyeCenterY = m_EyeY+m_Longthofview_w*sin(m_Angle);
	m_EyeCenterZ = m_EyeZ-m_Longthofview*cos(m_Elev);

	gluLookAt( m_EyeX, m_EyeY, m_EyeZ, m_EyeCenterX, m_EyeCenterY, m_EyeCenterZ, 0.0, 0.0, 1.0 );

   	if( m_CurrentWMIdx >= 0 )
   	{
   		m_WorldModel.WM( m_CurrentWMIdx )->Render();
   	}

	Analyse();
}
void RenderWidget::resizeGL( int width, int height )
{
	if ( height == 0 )
	{
		height = 1;
	}

	glViewport( 0, 0, (GLint)width, (GLint)height );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
}
unsigned int RenderWidget::WMSize()
{
	return m_WorldModel.Size();
}
void RenderWidget::SetCurrentWM( int idx )
{
	m_CurrentWMIdx = idx;
	updateGL();
}
int RenderWidget::GetCurrentWM()
{
	return m_CurrentWMIdx;
}
float RenderWidget::GetTime()
{
	return m_WorldModel.WM( m_CurrentWMIdx )->Time();
}
std::string RenderWidget::NameLeftTeam()
{
	return m_WorldModel.WM(m_CurrentWMIdx)->NameTeamLeft();
}
std::string RenderWidget::NameRightTeam()
{
	return m_WorldModel.WM(m_CurrentWMIdx)->NameTeamRight();
}
float RenderWidget::ScoreTeamLeft()
{
	return m_WorldModel.WM(m_CurrentWMIdx)->ScoreTeamLeft();
}
float RenderWidget::ScoreTeamRight()
{
	return m_WorldModel.WM(m_CurrentWMIdx)->ScoreTeamRight();
}
void RenderWidget::ResetViewPointInitial()
{
	m_EyeX = 0.0;
	m_EyeY = -6.0;
	m_EyeZ = 6.0;
	m_EyeCenterX = 0.0;
	m_EyeCenterY = 0.0;
	m_EyeCenterZ = 0.0;

	m_Longthofview_w = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY );
	m_Longthofview = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY + m_EyeZ*m_EyeZ );
	m_Elev=atan2(m_Longthofview_w,m_EyeZ);
	m_Angle=atan2(fabs(m_EyeY),m_EyeX);
}
void RenderWidget::ResetViewPointHeight()
{
	m_EyeX = 0.0;
	m_EyeY = -3.0;
	m_EyeZ = 18.0;
	m_EyeCenterX = 0.0;
	m_EyeCenterY = 0.0;
	m_EyeCenterZ = 0.0;

	m_Longthofview_w = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY );
	m_Longthofview = sqrt( m_EyeX*m_EyeX + m_EyeY*m_EyeY + m_EyeZ*m_EyeZ );
	m_Elev=atan2(m_Longthofview_w,m_EyeZ);
	m_Angle=atan2(fabs(m_EyeY),m_EyeX);
}
void RenderWidget::OutputCurrentLog()
{
	int currentWMIdx = m_CurrentWMIdx;
	WorldModelNode* wm = m_WorldModel.WM(currentWMIdx);
	std::ostringstream oss;
	oss << "Snapshot_" << NameLeftTeam() << "_" << NameRightTeam() 
		<< "_" << wm->Time() << "_" << currentWMIdx;

	PaintCurrentLog( oss.str() );
	oss << ".log";

	std::ofstream fop;
	fop.open( oss.str().c_str() );

	while( wm->mNeedLoadOmittedInfo )
	{
		wm = m_WorldModel.WM(currentWMIdx--);
	}

	while( currentWMIdx <= m_CurrentWMIdx )
	{
		wm = m_WorldModel.WM(currentWMIdx++);
		fop << wm->Context();
	}

	fop.close();
}
void RenderWidget::PaintCurrentLog( const std::string& fileName )
{
	std::ostringstream oss_1;
	std::ostringstream oss_2;
	oss_1 << fileName << ".png";
	oss_2 << fileName << "_2D.png";

	QPixmap snapshotPixmap = QPixmap::grabWindow(this->winId());  
	snapshotPixmap.save(oss_1.str().c_str());

	double eyeX = m_EyeX; 
	double eyeY = m_EyeY;
	double eyeZ = m_EyeZ;
	double centerEyeX = m_EyeCenterX;
	double centerEyeY = m_EyeCenterY;
	double centerEyeZ = m_EyeCenterZ;
	double longthofview_w = m_Longthofview_w;
	double longthofview = m_Longthofview;
	double elev = m_Elev;
	double angle = m_Angle;

	ResetViewPointHeight();
	updateGL();
	snapshotPixmap = QPixmap::grabWindow(this->winId());  
	snapshotPixmap.save(oss_2.str().c_str());

	m_EyeX = eyeX; 
	m_EyeY = eyeY;
	m_EyeZ = eyeZ;
	m_EyeCenterX = centerEyeX;
	m_EyeCenterY = centerEyeY;
	m_EyeCenterZ = centerEyeZ;
	m_Longthofview_w = longthofview_w;
	m_Longthofview = longthofview;
	m_Elev = elev;
	m_Angle = angle;

	updateGL();
}
void RenderWidget::SetPause()
{
	m_Pause = !m_Pause;
}
void RenderWidget::Analyse()
{
	m_ObjPos.clear();
	AnalyseBall();
	AnalyseAgentPos();
}
void RenderWidget::AnalyseBall()
{
	Analyser analyser;
	analyser.SetSearchTime( GetTime() );
	ObjPos ballPos;
	analyser.SetSearchObjName( "ball" );
	analyser.SearchInfo( m_WorldModel.WM(m_CurrentWMIdx), ballPos.pos );
	m_ObjPos["ball"] = ballPos;
}
void RenderWidget::AnalyseAgentPos()
{
	std::vector<AgentInfo> agentInfoVec;
	Analyser analyser;
	analyser.AnalyseAgentInfo( m_WorldModel.WM(m_CurrentWMIdx), agentInfoVec );
	for( unsigned int i = 0; i < agentInfoVec.size(); i ++ )
	{
		std::string name = agentInfoVec[i].name;
		ObjPos agentPos;
		for( unsigned j = 0; j < 16;j ++ )
		{
			agentPos.pos[j] = agentInfoVec[i].pos[j];
		}

		m_ObjPos[name] = agentPos;
// 		std::cout<< agentInfoVec[i].name << "\n";
// 		for( int j = 0; j < 16; j ++ )
// 		{
// 			std::cout<< agentInfoVec[i].pos[j] << " ";
// 			if( j % 4 == 3 )
// 			{
// 				std::cout<< "\n";
// 			}
// 		}
// 		std::cout<< "\n";
	}
}
void RenderWidget::mousePressEvent(QMouseEvent *evt)
{
	lastPos = evt->pos();
}
void RenderWidget::mouseMoveEvent(QMouseEvent *evt)
{
	int dx = evt->x() - lastPos.x();
	int dy = evt->y() - lastPos.y();

	if( evt->buttons() & Qt::LeftButton ) 
 	{
		m_Elev -= dy * CameraSpeed * 0.05;     
		m_Angle -= dx * CameraSpeed * 0.05;
		updateGL();
 	} 

	lastPos = evt->pos();
}
void RenderWidget::keyPressEvent(QKeyEvent *evt)
{
	const int unit_dist = 1;

 	if( evt->key() == Qt::Key_W )
 	{
		m_EyeY += sin(m_Angle) * CameraSpeed;
		m_EyeX += cos(m_Angle) * CameraSpeed;
 	}
 	else if( evt->key() == Qt::Key_S )
 	{
		m_EyeY -= sin(m_Angle) * CameraSpeed;
		m_EyeX -= cos(m_Angle) * CameraSpeed;
	}
	else if( evt->key() == Qt::Key_A )
	{
		m_EyeY += sin(m_Angle + PI/2.0) * CameraSpeed;
		m_EyeX += cos(m_Angle + PI/2.0) * CameraSpeed;
	}
	else if( evt->key() == Qt::Key_D )
	{
		m_EyeY -= sin(m_Angle + PI/2.0) * CameraSpeed;
		m_EyeX -= cos(m_Angle + PI/2.0) * CameraSpeed;
	}
	else if( evt->key() == Qt::Key_Z )
	{
		m_EyeZ += CameraSpeed;
	}
	else if( evt->key() == Qt::Key_X )
	{
		m_EyeZ -= CameraSpeed;
	}
 	else if( evt->key() == Qt::Key_R )
 	{
		RenderObj::GetInstance()->SetRenderMode( 0 );
 		ResetViewPointInitial();
 	}
	else if( evt->key() == Qt::Key_H )
	{
		RenderObj::GetInstance()->SetRenderMode( 1 );
		ResetViewPointHeight();
	}
	else if( evt->key() == Qt::Key_F1 )
	{
		OutputCurrentLog();
	}
	else if( evt->key() == Qt::Key_Left )
	{
		m_CurrentWMIdx -=10;
		emit CurrentWM( m_CurrentWMIdx );
	}
	else if( evt->key() == Qt::Key_Right )
	{
		m_CurrentWMIdx +=10;
		emit CurrentWM( m_CurrentWMIdx );
	}
	else if ( evt->key() == Qt::Key_Space )
	{
		SetPause();
	}

	updateGL();
}
void RenderWidget::keyReleaseEvent(QKeyEvent *evt)
{
	//std::cout<< evt->key() << " ==== " << evt->isAutoRepeat() << "\n";
}
void RenderWidget::timerEvent( QTimerEvent * evt )
{
	if( !m_Pause )
	{
		m_CurrentWMIdx ++;
		emit CurrentWM( m_CurrentWMIdx );
		updateGL();
	}
}